﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FinalsArithmetic.Test
{
	public class Calculate
	{
		private int TotalCount = 0; //总人数
		private List<MatchInfo> matchInfoList = new List<MatchInfo>(); //人工匹配信息列表
		public Calculate(int totalCount, List<MatchInfo> theMatchInfoList)
		{
			TotalCount = totalCount;
			matchInfoList = theMatchInfoList;
		}

		public List<Seat> GetSeatInfoList()
		{
			//座位自数据初始化
			List<Seat> seatList = new List<Seat>();
			for (int i = 1; i <= TotalCount; i++)
			{
				seatList.Add(new Seat
				{
					SeatId = i,
					AnchorId = 0
				});
			}

			////人工干预 给主播安排位置
			//// 1/4决赛，此时剩余8人
			//int finalsId = 4;
			////4堆：1-8，9-16，17-24，25-32
			//ArrangeSeat(ref seatList, matchInfoList, finalsId);

			//// 1/8决赛，此时剩余16人
			//finalsId = 8;
			////8堆：1-4，5-8，9-12，13-16，17-20，21-24，25-28，29-32
			//ArrangeSeat(ref seatList, matchInfoList, finalsId);

			foreach (var finalsId in matchInfoList.OrderBy(m => m.FinalsId).Select(m => m.FinalsId).Distinct().ToList())
			{
				ArrangeSeat(ref seatList, matchInfoList.Where(m => m.FinalsId == finalsId).ToList(), finalsId);
			}

			return seatList;
		}

		/// <summary>
		/// 给主播安排位置（人工干预）
		/// </summary>
		/// <param name="seatList"></param>
		/// <param name="matchInfoList"></param>
		/// <param name="finalsId"></param>
		void ArrangeSeat(ref List<Seat> seatList, List<MatchInfo> finalsMatchInfoList, int finalsId)
		{
			foreach (var finalsMatchInfo in finalsMatchInfoList)
			{
				//先给主播1安排位置，再给主播2安排位置（思路：选择区域【即分组】时不用随机选择，直接按照顺序安排即可）
				//此时共分成了几堆
				int pileCount = finalsMatchInfo.FinalsId;
				//计算 可以将主播1安排在第几堆（给主播1安排座位）
				ArrangeAnchor1(finalsMatchInfo.AnchorId1, seatList, pileCount, out bool isSuccess);
				if (!isSuccess)
				{
					throw new Exception("失败1");
				}
				//计算 可以将主播2安排在第几堆（给主播2安排座位）
				ArrangeAnchor2(finalsMatchInfo, seatList, pileCount, out isSuccess);

				//ArrangeAnotherAnchor(ref seatList, finalsMatchInfo, out isSuccess);

				if (!isSuccess)
				{
					throw new Exception("失败2");
				}
			}
		}

		///// <summary>
		///// 递归 优先 为更深层的比赛的另一个主播安排座位
		///// </summary>
		///// <param name="seatList"></param>
		///// <param name="finalsMatchInfo"></param>
		///// <param name="isSuccess"></param>
		//void ArrangeAnotherAnchor(ref List<Seat> seatList, MatchInfo finalsMatchInfo, out bool isSuccess)
		//{
		//	isSuccess = true;
		//	//同时 优先 为所有的FinalsId*2 中包含的对决中存在的相同id的主播分配座位
		//	var deeperFinalsMatchInfoList = matchInfoList.Where(m => m.FinalsId == finalsMatchInfo.FinalsId * 2)
		//		.Where(m => new List<int> { m.AnchorId1, m.AnchorId2 }.Any(a => new List<int> { finalsMatchInfo.AnchorId1, finalsMatchInfo.AnchorId2 }.Any(b => b == a)))
		//		.ToList();
		//	if (deeperFinalsMatchInfoList.Any())
		//	{
		//		foreach (var deeperFinalsMatchInfo in deeperFinalsMatchInfoList)
		//		{
		//			int pileCount = deeperFinalsMatchInfo.FinalsId;
		//			ArrangeAnchor2(deeperFinalsMatchInfo, seatList, pileCount, out isSuccess);

		//			ArrangeAnotherAnchor(ref seatList, deeperFinalsMatchInfo, out isSuccess);

		//			var newDeeperFinalsMatchInfo = new MatchInfo
		//			{
		//				FinalsId = deeperFinalsMatchInfo.FinalsId,
		//				AnchorId1 = deeperFinalsMatchInfo.AnchorId2,
		//				AnchorId2 = deeperFinalsMatchInfo.AnchorId1,
		//			};
		//			ArrangeAnchor2(newDeeperFinalsMatchInfo, seatList, pileCount, out isSuccess);

		//			ArrangeAnotherAnchor(ref seatList, newDeeperFinalsMatchInfo, out isSuccess);
		//		}
		//	}
		//	else
		//	{

		//	}
		//}


		/// <summary>
		/// 计算 可以将主播1安排在第几堆（给主播1安排座位）
		/// </summary>
		/// <param name="anchor1Id"></param>
		/// <param name="seatList"></param>
		/// <param name="pileCount"></param>
		/// <param name="isSuccess"></param>
		void ArrangeAnchor1(int anchor1Id, List<Seat> seatList, int pileCount, out bool isSuccess)
		{
			//将主播1优先安排在空位最多的堆中（思路：根据空位的多少，由多到少排序）
			List<List<Seat>> allPileSeatList = new List<List<Seat>>();
			for (int pileIndex = 1; pileIndex <= pileCount; pileIndex++)
			{
				var pileSeatList = seatList.Skip((pileIndex - 1) * (TotalCount / pileCount)).Take(TotalCount / pileCount).ToList();
				allPileSeatList.Add(pileSeatList);
			}
			allPileSeatList = allPileSeatList.OrderByDescending(m => m.Count(k => k.AnchorId <= 0)).ToList();


			isSuccess = false; //判断是否分配成功了
			for (int pileIndex = 1; pileIndex <= allPileSeatList.Count(); pileIndex++)
			{
				var pileSeatList = allPileSeatList[pileIndex - 1];// seatList.Skip((pileIndex - 1) * (TotalCount / pileCount)).Take(TotalCount / pileCount).ToList();

				//判断该堆是否可以安排主播1
				//如果该主播1已经被分配，则直接返回
				if (seatList.Any(m => m.AnchorId == anchor1Id))
				{
					isSuccess = true;
					return;
				}
				//如果该堆中座位满了，则不能安排，则在下一堆中寻找位置
				if (pileSeatList.All(m => m.AnchorId > 0))
				{
					continue;
				}
				//至少需要两个坑位
				if (pileSeatList.Count(m => m.AnchorId <= 0) < 2)
				{
					continue;
				}
				//随机在该堆中找一个空位置分配给主播1
				int seatId = GetEmptySeatId(pileSeatList);
				//将座位分配给主播1
				seatList.FirstOrDefault(m => m.SeatId == seatId).AnchorId = anchor1Id;
				isSuccess = true;
				return;
			}
		}

		/// <summary>
		/// 计算 可以将主播2安排在第几堆（给主播2安排座位）
		/// </summary>
		/// <param name="finalsMatchInfo"></param>
		/// <param name="seatList"></param>
		/// <param name="pileCount"></param>
		/// <param name="isSuccess"></param>
		void ArrangeAnchor2(MatchInfo finalsMatchInfo, List<Seat> seatList, int pileCount, out bool isSuccess)
		{
			isSuccess = false; //判断是否分配成功了

			for (int pileIndex = 1; pileIndex <= pileCount; pileIndex++)
			{
				var pileSeatList = seatList.Skip((pileIndex - 1) * (TotalCount / pileCount)).Take(TotalCount / pileCount).ToList();
				//判断该堆是否可以安排主播2
				//如果已经把该主播2分配到该堆中，则直接返回
				if (seatList.Any(m => m.AnchorId == finalsMatchInfo.AnchorId2))
				{
					isSuccess = true;
					return;
				}
				//座位满了，则不能安排，则在下一堆中寻找位置
				if (pileSeatList.All(m => m.AnchorId > 0))
				{
					continue;
				}
				//如果该堆中没有主播1的存在，则跳过，就在下一堆中寻找位置
				var pileSeat1 = pileSeatList.FirstOrDefault(m => m.AnchorId == finalsMatchInfo.AnchorId1);
				if (pileSeat1 == null)
				{
					continue;
				}

				//递归查找最多空位的分堆
				SearchPileSeatList(ref pileSeatList, seatList, pileSeat1.SeatId, pileCount, finalsMatchInfo.AnchorId2);

				int seatId = GetEmptySeatId(pileSeatList);
				//将座位分配给主播2
				seatList.FirstOrDefault(m => m.SeatId == seatId).AnchorId = finalsMatchInfo.AnchorId2;
				isSuccess = true;
				return;
			}
		}

		public void SearchPileSeatList(ref List<Seat> pileSeatList, List<Seat> seatList, int pileSeat1Id, int pileCount, int anchor2Id)
		{
			//优先从下级的异堆中找，如果异堆中没有位置了，那就在原堆中随便选一个（尽量将主播2安排在新堆中的异堆里）
			var newPileCount = pileCount * 2;
			if (newPileCount > seatList.Count() / 2)
			{
				return;
			}
			//先计算主播1在新堆中的第几堆
			var newPileIndex1 = (pileSeat1Id - 1 + TotalCount / newPileCount) / (TotalCount / newPileCount);
			var newPileIndex2 = 0;
			if (newPileIndex1 % 2 == 0)
			{
				newPileIndex2 = newPileIndex1 - 1;
			}
			else
			{
				newPileIndex2 = newPileIndex1 + 1;
			}
			//获取异堆的数据
			var newPileSeatList = seatList.Skip((newPileIndex2 - 1) * (TotalCount / newPileCount)).Take(TotalCount / newPileCount).ToList();

			//如果异堆中还有坑位，则优先放到异堆中
			if (newPileSeatList.Any(m => m.AnchorId <= 0))
			{
				pileSeatList = newPileSeatList;

				//如果异堆中空位置的个数等于 TotalCount / newPileCount，则在异堆中随便选一个位置即可，但是如果坑位小于TotalCount / newPileCount，则继续细分
				if (pileSeatList.Count(m => m.AnchorId <= 0) < TotalCount / newPileCount)
				{
					//优先找上决赛中的人工规则中的与之关联的主播id，如果不存在，则随便取一个主播id，这里取第一个主播id，然后继续递归向更深一级查找空位最多的分堆
					int newSeatId = pileSeatList.FirstOrDefault(m => m.AnchorId > 0).SeatId;
					var theMatchInfoList = matchInfoList.Where(m => m.FinalsId == newPileCount).ToList();
					var matchInfo = theMatchInfoList.FirstOrDefault(m => m.AnchorId1 == anchor2Id);
					if (matchInfo != null)
					{
						var pileSeatInfo = pileSeatList.FirstOrDefault(m => m.AnchorId == matchInfo.AnchorId2);
						if (pileSeatInfo != null)
						{
							newSeatId = pileSeatInfo.SeatId;
						}
					}
					else
					{
						matchInfo = theMatchInfoList.FirstOrDefault(m => m.AnchorId2 == anchor2Id);
						if (matchInfo != null)
						{
							var pileSeatInfo = pileSeatList.FirstOrDefault(m => m.AnchorId == matchInfo.AnchorId1);
							if (pileSeatInfo != null)
							{
								newSeatId = pileSeatInfo.SeatId;
							}
						}
					}
					SearchPileSeatList(ref pileSeatList, seatList, newSeatId, newPileCount, anchor2Id);
				}
				else
				{
					//不作处理，随便选位置
				}
			}
			else
			{
				//获取同堆的数据，进行细分
				pileSeatList = seatList.Skip((newPileIndex1 - 1) * (TotalCount / newPileCount)).Take(TotalCount / newPileCount).ToList();
				SearchPileSeatList(ref pileSeatList, seatList, pileSeat1Id, newPileCount, anchor2Id);
			}
		}

		/// <summary>
		/// 随机获取可用的空位置的位置id
		/// </summary>
		/// <param name="pileSeatList"></param>
		/// <returns></returns>
		private static int GetEmptySeatId(List<Seat> pileSeatList)
		{
			//获取该堆中剩下的还未被安排的空位置
			var otherSeatList = pileSeatList.Where(m => m.AnchorId <= 0).ToList();

			List<EmptySeatInfo> emptySeatInfoList = new List<EmptySeatInfo>();
			for (int i = 0; i < otherSeatList.Count(); i++)
			{
				emptySeatInfoList.Add(new EmptySeatInfo() { Index = i, SeatId = otherSeatList[i].SeatId });
			}
			List<int> list = new List<int>();
			ListHelper.RandomNotEqualList(ref list, emptySeatInfoList.Min(m => m.Index), emptySeatInfoList.Max(m => m.Index), 1);
			//给主播分配的座位id（分配成功）
			int seatId = emptySeatInfoList.FirstOrDefault(m => m.Index == list.First()).SeatId;
			return seatId;
		}










		/// <summary>
		/// 座位类
		/// </summary>
		public class Seat
		{
			/// <summary>
			/// 座位id（值是从1到总人数的值依次排列，优先初始化的字段）
			/// </summary>
			public int SeatId { get; set; }
			/// <summary>
			/// 该座位上的主播id
			/// </summary>
			public int AnchorId { get; set; }
		}


		/// <summary>
		/// 主播类
		/// </summary>
		public class Anchor
		{
			/// <summary>
			/// 主播id
			/// </summary>
			public int AnchorId { get; set; }
			/// <summary>
			/// 主播昵称
			/// </summary>
			public string AnchorName { get; set; }
		}


		/// <summary>
		/// 人工匹配信息类
		/// </summary>
		public class MatchInfo
		{
			/// <summary>
			/// 决赛Id
			/// </summary>
			public int FinalsId { get; set; }
			/// <summary>
			/// 主播1的id
			/// </summary>
			public int AnchorId1 { get; set; }
			/// <summary>
			/// 主播2的id（与主播1对打的主播）
			/// </summary>
			public int AnchorId2 { get; set; }
		}


		/// <summary>
		/// 空座位索引信息类
		/// </summary>
		public class EmptySeatInfo
		{
			/// <summary>
			/// 空位置的下标索引
			/// </summary>
			public int Index { get; set; }
			/// <summary>
			/// 空位置的id
			/// </summary>
			public int SeatId { get; set; }
		}






		/// <summary>
		/// 座位信息类（显示用，与逻辑无关）
		/// </summary>
		public class SeatInfo
		{
			/// <summary>
			/// 座位id（值是从1到总人数的值依次排列，优先初始化的字段）
			/// </summary>
			public int SeatId { get; set; }
			/// <summary>
			/// 该座位上的主播信息
			/// </summary>
			public Anchor Anchor { get; set; }
		}
	}
}
